美团2018.9.6笔试 图的遍历

题目描述

给定N个点、N-1条边的无向连通图,节点从1到N编号,每条边的长度均为1。假设你从1节点出发并打算遍历所有节点,那么总路程至少是多少?
输入:
第一行包含一个整数N,1≤N≤ 1 0 5 10^5 105
接下来N-1行,每行包含两个整数X和Y,表示X号节点和Y号节点之间有一条边,1≤X,Y≤N
输出:
输出总路程的最小值
样例输入:
4
1 2
1 3
3 4
样例输出:
4
提示:
按1->2->1->3->4的路线遍历所有节点,总路程为4

思路

首先看到程序总是从1开始遍历,可以想到这个1其实就是树的根节点,本题本质上一棵树的深度遍历问题。
看到N个节点,N-1边,而且还是连通图,所以可以确定这个图,实际上是一颗生成树。同时,因为是树,所以肯定没有环。
以具体例子分析:
样例输入的图是这样的:
这里写图片描述
从1出发遍历,找到深度最深的那条路线,那么这条路线上的边只会走一次,而其他边则都会走两遍。之所以要找到深度最深的那条路线,因为这样就可以让走两遍的边的数量最小。
所以,红线就是代表深度最深的那条路线,这条路线只会走一次;而黑线的路线,就会走两遍。

对于更复杂的图也是如此(本文代码用的是这个图):
这里写图片描述

重新整理思路
1.输入的数据是图的数据,而我们需要将其改成树的数据。所以,从根节点1开始深度遍历,用数据结构记录下来树的结构和树各节点的深度。
2.找出深度最深的那条路线,那么这条路线上的边乘1,加上其余边乘2,就是结果。(deep数组记录各节点深度,deep数组中的最大值就是最大深度)
3.假设这条路线的长度为m(最大深度),那么其他边的数量为N-1-m

代码

from collections import defaultdict
#提交代码时,取消以下注释
##n = eval(input())
##edge = []
##for i in range(n-1):
##    a,b = map(int,input().split())
##    edge.append([a,b])

#提交代码时,删除以下代码
n =7
edge = [[1,2],[2,3],[2,4],[3,6],[6,7],[3,5]]

d =defaultdict(list)#邻接表
for i in edge:
    #无向图添加两条边
    d[i[0]].append(i[1])
    d[i[1]].append(i[0])
#建立好了邻接表
#深度遍历

visited = [False]*(n+1)#使用索引从1开始

deep = [0]*(n+1)#记录每个节点的深度
parent = [-1]*(n+1)#记录每个节点的父节点

def recursion(d,n,tempdeep):
    tempdeep += 1
    visited[n] = True
    if d[n] == []:#已经为空了,就回溯
        return 
    for i in d[n]:
        if (visited[i] == False):
            deep[i] = tempdeep
            parent[i] = n
            recursion(d,i,tempdeep)
recursion(d,1,0)

#找到最大深度的路线的长度,即路线上有多少条边
maxdeep = max(deep)
print( maxdeep + (n-1-maxdeep)*2 )

运行结果为8
解析:
parent记录下来了树的结构,但此代码中没有用处。

有一种更笨的方法来获得最深路线长度(大家可以无视,只是想看下这个递归怎么写):

#找出深度最大那个节点的索引
maxdeepindex = deep.index(max(deep))
#得到最深节点到根节点的路线的长度
def findroot(parent,temp):
    if(temp == 1):
        return 0
    return 1+findroot(parent,parent[temp])
print(findroot(parent,maxdeepindex))

运行结果为4,即为最深深度。

2019.8.24代码调整(修改递归代码,使之更简洁易懂):

from collections import defaultdict
#提交代码时,取消以下注释
n = eval(input())
edge = []
for i in range(n-1):
    a,b = map(int,input().split())
    edge.append([a,b])

d =defaultdict(list)#邻接表
for i in edge:
    #无向图添加两条边
    d[i[0]].append(i[1])
    d[i[1]].append(i[0])
#建立好了邻接表
#深度遍历

visited = [False]*(n+1)#使用索引从1开始

deep = [0]*(n+1)#记录每个节点的深度

def recursion(d,n,tempdeep):
    deep[n] = tempdeep
    visited[n] = True
    if d[n] == []:#已经为空了,就回溯
        return 
    for i in d[n]:
        if (visited[i] == False):
            recursion(d,i,tempdeep+1)
recursion(d,1,0)

#找到最大深度的路线的长度,即路线上有多少条边
maxdeep = max(deep)
print( maxdeep + (n-1-maxdeep)*2 )

但牛客还是报错(66.7%,具体看评论),很恶心的是牛客网不提供出错的输入,和期望的输出。思路是对的,希望有明白的盆友能指点一二。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
《深度学习笔试100题.docx》是一份涵盖深度学习领域的笔试试题文档,本文档的题目数量为100道,涉及的知识面广泛,包括深度学习的基础理论、算法原理、模型应用等方面。笔试题的形式有选择题、填空题、判断题等多种类型,考察了考生对深度学习知识的全面掌握程度。 针对这份试题文档,考生可以通过认真学习深度学习的相关知识,包括卷积神经网络、循环神经网络、深度学习模型的训练和优化等内容,以及深度学习在计算机视觉、自然语言处理等领域的应用案例。在准备考试的过程中,可以通过参考相关的教材、学习笔记、在线课程等途径来加深对深度学习知识的理解和掌握。 在回答试题的过程中,考生需要对每道题目进行认真思考、分析和解答,注意理清题目要求和逻辑关系,结合所学知识进行答题。需要指出的是,深度学习领域的知识体系庞大而复杂,因此考生在备考过程中要注重系统性和全面性,做到知识点的扎实掌握,并且在解题过程中注重方法和思路的合理运用。 总的来说,对于《深度学习笔试100题.docx》,考生应以认真学习和全面理解相关知识为前提,结合试题的题目类型和知识点深度进行答题准备,注重方法和思路的运用,在解答过程中注意逻辑严谨和表达清晰,力争做到全面、准确地掌握深度学习领域的知识。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值